/**
 * Title:		KFrogDecimal.java
 * Description: This class is used to represent decimal data type. 
 * 
 * @version		1.0 May 2009
 * @author		Rami Habas
 */

package kfrog.type;

public class KFrogDecimal extends KFrogDataType {

	/** variable value */
	private int variable;

	/**
     * Constructor used to instantiate a variable of decimal type
     * 
     * @param variable   The initial value
     */
	public KFrogDecimal(int variable) {
		super();
		this.variable = variable;
		init = true;
	}

	/**
     * Default Constructor instantiates a variable with a default value of 0.
     */
	public KFrogDecimal() {
		this(0);
		init = false;
	}

	/**
     * Useful method that returns the integer value of the given KFrogDataType
     * variable
     * 
     * @param b   KFrogDataType variable
     */
	public static int decimalValue(KFrogDataType b) {
		b.initCheck();

		if (b instanceof KFrogDecimal)
			return ((KFrogDecimal)b).variable;

		if (b instanceof KFrogReal)
			return (int)((KFrogReal)b).getVariable();

		throw new RuntimeException("Cannot cast to decimal value");
	}
	
	/** decimal type copy method */
	public KFrogDataType copy() {
		initCheck();
		return new KFrogDecimal(variable);
	}

	/** instantiate a new decimal type */
	public KFrogDataType newType() {
		return new KFrogDecimal();
	}

	public String typeName() {
		return "decimal";
	}

	/** get the decimal value as String */
	public String getValue() {
		initCheck();
		return String.valueOf(variable);
	}

	/** get the decimal value as an int */
	public int getVariable() {
		initCheck();
		return variable;
	}

	/** perform addition and widen to KFrogReal if needed */
	public KFrogDataType plus(KFrogDataType b) {
		initCheck();

		if (b instanceof KFrogDecimal)
			return new KFrogDecimal(variable + decimalValue(b));

		return new KFrogReal(variable + KFrogReal.realValue(b));
	}

	/** perform subtraction and widen to KFrogReal if needed */
	public KFrogDataType minus(KFrogDataType b) {
		initCheck();

		if (b instanceof KFrogDecimal)
			return new KFrogDecimal(variable - decimalValue(b));

		return new KFrogReal(variable - KFrogReal.realValue(b));
	}

	/** perform multiplication and widen to KFrogReal if needed */
	public KFrogDataType times(KFrogDataType b) {
		initCheck();

		if (b instanceof KFrogDecimal)
			return new KFrogDecimal(variable * decimalValue(b));

		return new KFrogReal(variable * KFrogReal.realValue(b));
	}

	/** perform division and widen to KFrogReal if needed */
	public KFrogDataType divide(KFrogDataType b) {
		initCheck();

		if (b instanceof KFrogDecimal)
			return new KFrogDecimal(variable / decimalValue(b));

		return new KFrogReal(variable/ KFrogReal.realValue(b));
	}

	/** perform modulo and widen to KFrogReal if needed */
	public KFrogDataType modulo(KFrogDataType b) {
		initCheck();

		if (b instanceof KFrogDecimal)
			return new KFrogDecimal(variable % decimalValue(b));

		return new KFrogReal(variable % KFrogReal.realValue(b));
	}

	public KFrogDataType prefixIncrement() {
		variableCheck();
		initCheck();
		return new KFrogDecimal(++variable);
	}

	public KFrogDataType postfixIncrement() {
		variableCheck();
		initCheck();
		return new KFrogDecimal(variable++);
	}

	public KFrogDataType prefixDecrement() {
		variableCheck();
		initCheck();
		return new KFrogDecimal(--variable);
	}

	public KFrogDataType postfixDecrement() {
		variableCheck();
		initCheck();
		return new KFrogDecimal(variable--);
	}

	/**
     * Perform the assignment a=b where a is this instance. Note that this can
     * also serve as an initialization so init=true. Also, cannot assign 
     * KFrogReal to KFrogDecimal.
     * 
     * @param b   KFrogDataType variable
     */
	public KFrogDataType assign(KFrogDataType b) {
		variableCheck();
		b.initCheck();

		if (b instanceof KFrogReal)
			throw new RuntimeException("precision loss");

		variable = decimalValue(b);
		init = true;
		return this;
	}

	public KFrogDataType isEqual(KFrogDataType b) {
		initCheck();

		if (b instanceof KFrogDecimal)
			return new KFrogLogical((decimalValue(b) == variable));

		return b.isEqual(this);
	}

	public KFrogDataType plusAssign(KFrogDataType b) {
		variableCheck();
		initCheck();
		variable+= decimalValue(b);
		return this;
	}

	public KFrogDataType minusAssign(KFrogDataType b) {
		variableCheck();
		initCheck();
		variable-= decimalValue(b);
		return this;
	}

	public KFrogDataType timesAssign(KFrogDataType b) {
		variableCheck();
		initCheck();
		variable*= decimalValue(b);
		return this;
	}

	public KFrogDataType divideAssign(KFrogDataType b) {
		variableCheck();
		initCheck();
		variable/= decimalValue(b);
		return this;
	}

	public KFrogDataType moduloAssign(KFrogDataType b) {
		variableCheck();
		initCheck();
		variable%= decimalValue(b);
		return this;
	}

	public KFrogDataType greaterThan(KFrogDataType b) {
		initCheck();
		if (b instanceof KFrogDecimal)
			return new KFrogLogical(variable > decimalValue(b));
		return b.lessThan(this);
	}

	public KFrogDataType greaterThanOrEqual(KFrogDataType b) {
		initCheck();
		if (b instanceof KFrogDecimal)
			return new KFrogLogical(variable >= decimalValue(b));
		return b.lessThanOrEqual(this);
	}

	public KFrogDataType lessThan(KFrogDataType b) {
		initCheck();
		if (b instanceof KFrogDecimal)
			return new KFrogLogical(variable < decimalValue(b));
		return b.greaterThan(this);
	}

	public KFrogDataType lessThanOrEqual(KFrogDataType b) {
		initCheck();
		if (b instanceof KFrogDecimal)
			return new KFrogLogical(variable <= decimalValue(b));
		return b.greaterThanOrEqual(this);
	}

	public KFrogDataType notEqual(KFrogDataType b) {
		initCheck();
		if (b instanceof KFrogDecimal)
			return new KFrogLogical(decimalValue(b) != variable);
		return b.notEqual(this);
	}

	public KFrogDataType unaryPlus() {
		initCheck();
		return new KFrogDecimal(+variable);
	}

	public KFrogDataType unaryMinus() {
		initCheck();
		return new KFrogDecimal(-variable);
	}
}
